home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Workbench Add-On
/
Workbench Add-On - Volume 1.iso
/
BBS-Archive
/
Dev
/
GNU-TILE-FORTH.lha
/
src
/
io.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-05-19
|
10KB
|
416 lines
/*
C BASED FORTH-83 MULTI-TASKING IO MANAGEMENT
Copyright (C) 1988-1990 by Mikael Patel
Computer Aided Design Laboratory (CADLAB)
Department of Computer and Information Science
Linkoping University
S-581 83 LINKOPING
SWEDEN
Email: mip@ida.liu.se
Started on: 30 June 1988
Last updated on: 26 June 1990
Dependencies:
(cc) fcntl.h, errno.h, kernel.h, error.h, memory.h and io.h
Description:
Handles low level access to Operating System to allow asynchronous
input and multi-tasking of Forth level processes while waiting for
buffer filling. File names are saved so that files are not reloaded.
Copying:
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <fcntl.h>
#include <errno.h>
#include "kernel.h"
#include "error.h"
#include "memory.h"
#include "io.h"
/* EXTERNAL DEFINED IO DISPATCH ROUTINE, ENVIRONMENT ACCESS AND ERROR CODE */
extern VOID io_dispatch();
extern CSTR getenv();
extern INT errno;
/* MAXIMUM FILE AND PATH NAME STRING SIZES */
#define FILENAMESIZE 128
#define PATHNAMESIZE 128
/* INFILE BUFFERS STACK AND STACK POINTER */
#define INFSTACKSIZE 32
INFILE_BUFFER io_infstack[INFSTACKSIZE];
INT io_infsp = -1;
/* OUTFILE AND ERROR FILE VARIABLES */
FILE *io_outf;
FILE *io_errf;
/* STACK OF NAMES OF LOADED FILE */
#define INFILESSIZE 64
static CSTR infiles[INFILESSIZE];
static INT infsp = -1;
/* STACK OF FILE SEARCH PATHS */
#define PATHSSIZE 32
static CSTR paths[PATHSSIZE];
static INT psp = -1;
/* IO MANAGEMENT DEFINITONS */
INT io_path(pname, pos)
CSTR pname; /* Pointer to path name */
INT pos; /* Position to append */
{
CHAR pathname[PATHNAMESIZE];
INT plen = strlen(pname);
INT i;
/* Check for null path. Dont add these */
if (plen == 0) return IO_NO_ERROR;
/* Check if the path name is an environment variable */
if (pname[0] == '$') {
/* Fetch the environment variables value */
char *paths = (char *) getenv((char *) pname + 1);
/* If paths are available recursivly add them to the path list */
if (paths) {
while (*paths) {
char *p = pathname;
/* Parse list of paths; directories seperated by colon */
while (*paths && *paths != ':') *p++ = *paths++;
*p++ = '\0';
/* Append recursively */
(VOID) io_path(pathname, pos);
/* Access next path if available */
if (*paths) paths++;
}
return IO_NO_ERROR;
}
else
return IO_UNKNOWN_PATH;
}
/* Check that the last character is a slash if not add it */
if (pname[plen - 1] != DIRSEPCHAR && pname[plen - 1] != ':') {
pname[plen++] = DIRSEPCHAR;
pname[plen] = '\0';
}
/* Check if the path has already been defined */
for (i = 0; i <= psp; i++)
if (STREQ(paths[i], pname)) return IO_PATH_DEFINED;
/* Check if space is available on path stack */
if (psp + 1 == PATHSSIZE) return IO_TOO_MANY_PATHS;
/* Make space for the new path */
psp = psp + 1;
/* Check where the path should be appended */
if (pos == IO_PATH_FIRST) {
for (i = psp; i > 0; i--) paths[i] = paths[i - 1];
pos = 0;
}
else pos = psp;
/* Add path string att position given */
paths[pos] = strcpy((char *) malloc((unsigned) plen + 1), pname);
return IO_NO_ERROR;
}
VOID io_flush()
{
/* Flush any waiting output */
(VOID) fflush(stdout);
/* Close all open files if not end of input stream */
if (io_not_eof()) {
/* Close all files but lowest */
while (io_infsp > 0) (VOID) close(io_infstack[io_infsp--] -> fd);
/* Close lowest file on file stack if not tty */
if (!isatty(io_infstack[io_infsp] -> fd))
(VOID) close(io_infstack[io_infsp--] -> fd);
}
}
INT io_infile(fname)
CSTR fname; /* Pointer to file name to open as input */
{
CHAR filename[FILENAMESIZE];
INT i, j;
INT fd;
/* Check for standard input as source */
if (fname == STDIN) {
/* Check if space is available on file stack */
if (io_infsp + 1 == INFSTACKSIZE) return IO_TOO_MANY_FILES;
/* Push standard input as source onto the file buffer stack */
io_infsp = io_infsp + 1;
io_infstack[io_infsp] -> fd = STDIN;
io_infstack[io_infsp] -> bufp = 0;
io_infstack[io_infsp] -> cc = 0;
io_infstack[io_infsp] -> fn = NIL;
io_infstack[io_infsp] -> ln = 1;
return IO_NO_ERROR;
}
/* Expand the file name using the path stack and try opening the file */
for (i = 0; i <= psp; i++) {
/* Build the new file name using a path */
(VOID) strcpy(filename, paths[i]);
(VOID) strcpy(filename + strlen(paths[i]), fname);
/* Check if this file has already been loaded */
for (j = 0; j <= infsp; j++)
if (STREQ(infiles[j], filename)) return IO_FILE_INCLUDED;
/* Try opening the file */
fd = open(filename, O_RDONLY);
/* If no errors then save the file name and return file descriptor */
if (fd != -1) {
/* Check if space is available on file stack */
if (io_infsp + 1 == INFSTACKSIZE) return IO_TOO_MANY_FILES;
/* Push file onto the file buffer stack and use it as source */
infsp = infsp + 1;
infiles[infsp] = strcpy((char *) malloc((unsigned) strlen(filename) + 1), filename);
io_infstack[++io_infsp] -> fd = fd;
io_infstack[io_infsp] -> bufp = 0;
io_infstack[io_infsp] -> cc = 0;
io_infstack[io_infsp] -> fn = infiles[infsp];
io_infstack[io_infsp] -> ln = 1;
return fd;
}
}
/* The file was not available so return error */
return IO_UNKNOWN_FILE;
}
INT io_fillbuf()
{
BOOL nonblocking;
/* Check io consistency and foreground task input only */
if (io_eof() || tp != foreground) error_fatal(0);
/* Flush any waiting output if filling buffer from a terminal */
if (isatty(io_infstack[io_infsp] -> fd)) (VOID) fflush(stdout);
/* Check for multi-tasking input operation */
if (tp != ((TASK) tp -> queue.succ)) {
(VOID) fcntl(io_infstack[io_infsp] -> fd, F_SETFL, FNDELAY);
tp -> status = IOWAITING;
nonblocking = TRUE;
}
else
nonblocking = FALSE;
/* Allow multi-tasking during waiting for input */
for (;;) {
/* Try reading a block from the current input stream */
if ((io_infstack[io_infsp] -> cc = read(io_infstack[io_infsp] -> fd,
io_infstack[io_infsp] -> buf,
BUFSIZE)) > 0) {
/* Restore to non-blocking input from file and foreground */
if (nonblocking) {
(VOID) fcntl(io_infstack[io_infsp] -> fd, F_SETFL, 0);
spush(foreground, TASK);
doresume();
tp -> status = RUNNING;
}
/* Initiate the buffer pointer and return the first character */
io_infstack[io_infsp] -> bufp = 0;
return io_getchar();
}
/* Did the read operation result in an end of file */
if (io_infstack[io_infsp] -> cc == 0 && errno != EWOULDBLOCK) {
/* Set back the file mode to synchronous and close the file */
if (nonblocking) {
(VOID) fcntl(io_infstack[io_infsp] -> fd, F_SETFL, 0);
spush(foreground, TASK);
doresume();
tp -> status = RUNNING;
}
(VOID) close(io_infstack[io_infsp--] -> fd);
/* Check if end of input source */
if (io_eof()) return IO_EOF;
/* Get character from previous file buffer */
return io_getchar();
}
/* Run forth level tasks while waiting for input */
if (tp == foreground) dodetach(); else doinner();
/* Check if the task for empty, i.e., only the foreground */
if (tp == foreground && tp == ((TASK) tp -> queue.succ)) {
(VOID) fcntl(io_infstack[io_infsp] -> fd, F_SETFL, 0);
nonblocking = FALSE;
}
/* Allow user extension of the io wait loop */
io_dispatch();
}
}
VOID io_skip(skpchr)
CHAR skpchr; /* Skip character */
{
CHAR c;
/* Skip all characters until skip termination character or end of file */
while (io_not_eof()) {
c = io_getchar();
if (c == '\n') io_newline();
if (c == skpchr) return;
}
}
VOID io_scan(buf, brkchr)
CSTR buf; /* Pointer to scan buffer */
CHAR brkchr; /* Break character */
{
CHAR c;
/* Initiate buffer as null string */
*buf = '\0';
/* Check for scanning until white space or special break character */
if (brkchr == ' ') {
/* While not white space or end of file */
while (io_not_eof()) {
c = io_getchar();
if (c == '\n') io_newline();
if (ISSPACE(c)) break;
*buf++ = c;
}
}
else {
/* While not the break character or end of file */
while (io_not_eof()) {
c = io_getchar();
if (c == '\n') io_newline();
if (c == brkchr) break;
*buf++ = c;
}
}
/* End the string and return */
*buf = '\0';
return;
}
VOID io_skipspace()
{
CHAR c;
/* Skip all white spaces */
while (io_not_eof()) {
c = io_getchar();
if (c == '\n') io_newline();
if (!ISSPACE(c)) break;
}
/* Step back the buffer pointer */
if (io_not_eof()) io_infstack[io_infsp] -> bufp -= 1;
}
VOID io_initiate(banner)
CSTR banner; /* Initiate application message */
{
INT i;
/* Assign output and error file */
io_outf = stdout;
io_errf = stderr;
/* Print banner and add initial paths */
(VOID) printf(banner);
(VOID) io_path("TILE:lib", IO_PATH_LAST);
(VOID) io_path("TILE:", IO_PATH_LAST);
(VOID) io_path("TILE:tst", IO_PATH_LAST);
(VOID) io_path("\"\"", IO_PATH_LAST);
/* Allocate file buffers */
for (i = 0; i < INFSTACKSIZE; i++) {
io_infstack[i] = (INFILE_BUFFER) malloc((unsigned) sizeof(file_buffer));
if (io_infstack[i] == NIL) {
(VOID) fprintf(io_errf, "io: cannot allocate file buffers\n");
exit(0);
}
}
}
VOID io_finish()
{
/* Flush any waiting output */
(VOID) fflush(stdout);
/* Close all open files */
while (io_not_eof()) (VOID) close(io_infstack[io_infsp--] -> fd);
}